package graph;

import list.*;

public class Edge {

	VertexPair vertexEnds;
	protected int weight;
	Edge partner;
	DListNode myNode;
	
	/** Edge constructor that assumes we have a partner edge. the partner edge will
	 *  update the partner field of the Edge object only if the partner will be in 
	 *  a different adjacency list (in other words, the 2 vertex objects v1 and v2
	 *  are NOT the same). 
	 * @param v1 is one of the vertices of the edge object
	 * @param v2 is the other vertex of this edge object
	 * @param weight is the weight of this edge,
	 * @param partner is the reference to the other edge object which is the "partner" 
	 * 	or other half edge
	 */
	public Edge (Object v1, Object v2, int weight, Edge partner) {

		vertexEnds = new VertexPair(v1,v2);
		this.weight = weight;
		this.partner = partner;
	}
	
	/** Edge() is an alternate constructor for edge that by default makes the partner
	 * edge null.
	 * @param v1 is one of the vertices of the edge
	 * @param v2 is the other vertex of this edge object
	 * @param weight is the weight of this edge.
	 */
	public Edge (Object v1, Object v2, int weight) {
		this(v1,v2,weight,null);
	}
	
	/** 
	 * otherVertex() returns the other vertex of the edge that does not match which the 
	 * given parameter. If it is a self-edge, then any one of the 2 vertices can be returned. 
	 * @param v is the vertex which we are trying to find the OTHER vertex for. In other words,
	 *  if this isn't a self-edge, then otherVertex should return the vertex of this edge that is 
	 *  NOT v. 
	 *  NOTE: If it is a self edge then v and the other edge are the same so it doesn't matter which we
	 *  return.
	 * @return a vertex end that is not v. This is the APPLICATION vertex, NOT the custom build
	 *  Vertex class (it is not the internal vertex representation) 
	 *  
	 *  Running time: O(1)
	 */
	protected Object otherVertex(Object v) {
		Object v1 = vertexEnds.object1;
		Object v2 = vertexEnds.object2;
		if (v == v1) {
			return v2;
		} else {
			return v1;
		}
	}
	
	
	/**
	 * removeMe() removes this edge from a vertex's edgeList (which is a DList that should contain
	 * only edge objects (edges that are incident to the vertex).
	 * Because every edge knows which node it is stored in, it can quickly call remove on the node
	 * and extract itself in constant time.
	 * 
	 * NOTE: Does NOT update the vertex's degree field.
	 * 
	 * Running time: O(1)
	 */
	
	protected void removeMe() {
		try { 
			myNode.remove();
		} catch (InvalidNodeException e) {
			Thread.dumpStack();
		}
	}
	
	/** 
	 * removeMeAndPartner() removes this edge from a vertex's edgeList field and if it has a partner,
	 * removes the partner edge from the graph also. 
	 * 
	 * NOTE: Does NOT update the vertex's degree field.
	 * 
	 * Running time: O(1)
	 */
	protected void removeMeAndPartner() {
		try {
			if (partner != null) {
				partner.removeMe();
				myNode.remove();
			} else {
				myNode.remove();
			}
		} catch (InvalidNodeException e) {
			Thread.dumpStack();
		}
	}
	
	/** 
	 * equals() returns true if the vertexEnds (the vertexPair object are equals() ) are equal. Or
	 * else it returns false.
	 * 
	 * Running time: O(1)
	 * 
	 * @return true if the two edges are equal. else false.
	 */
	public boolean equals(Edge e) {
		if (e.weight == weight && e.vertexEnds.equals(vertexEnds)) {
			return true;
		}
		return false;
	}
	
	/** 
	 * toString() returns a string representation of this edge.
	 * @return a String representation of this edge with the 2 vertices (application version) and
	 *  the associated weight; 
	 */
	public String toString() {
		String s = "";
		s = "[Edge (" + vertexEnds.object1.toString() + " , " + vertexEnds.object2.toString() + " weight: " + weight +  " ]";
		return s;
	}
	
	
}
